package com.lee.rpc.protocal.spring.reference;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import com.lee.rpc.protocal.annotation.LiRemoteReference; 

public class SpringRpcReferencePostProcessor implements BeanFactoryPostProcessor,ApplicationContextAware, BeanClassLoaderAware{

	private ClassLoader classLoader;
	private ApplicationContext context;
	private RpcClientProperties rpcClientProperties;
	
	//保存发布的引用的bean信息
	private final Map<String, BeanDefinition> rpcRefBeanDefinition = new ConcurrentHashMap<>();
	
	 
	//constructor
	public SpringRpcReferencePostProcessor(RpcClientProperties rpcClientProperties) {
		this.rpcClientProperties = rpcClientProperties; 
	}
	
	
	
	/**
	 * 对象实例化之前调用，即bean被扫描之后都会变成BeanDefinition
	 * 因此，这里可以拿到所有的BeanDefinition，然后判断是否加了指定的注解
	 * */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		// TODO Auto-generated method stub
		String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
		for(String beanName : beanDefinitionNames) {
			BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
			String beanClassName = beanDefinition.getBeanClassName();
			if(null!=beanClassName && !"".equals(beanClassName)) { 
				Class<?> clazz = ClassUtils.resolveClassName(beanClassName, this.classLoader);
				//该方法遍历class对象中所有的field属性，把他作为参数传给回调方法parseRpcReference中
				ReflectionUtils.doWithFields(clazz, this::parseRpcReference);
			}
		}
		//注入到容器里面
		BeanDefinitionRegistry registry =  (BeanDefinitionRegistry)beanFactory;
		this.rpcRefBeanDefinition.forEach((beanName, beanDefinition)->{
			if(context.containsBean(beanName)) {
				return;
			}
			registry.registerBeanDefinition(beanName, beanDefinition);
		});
		
		
	}

	private void parseRpcReference(Field field) {
		LiRemoteReference liRemoteReference = AnnotationUtils.getAnnotation(field, LiRemoteReference.class);
		if(null != liRemoteReference) {
			//得到SpringRpcReferenceBean类的builder
			BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(SpringRpcReferenceBean.class);
			//给SpringRpcReferenceBean进行属性赋值
			System.out.println("field.getType():"+field.getType());
			beanDefinitionBuilder.addPropertyValue("interfaceClass", field.getType());
			beanDefinitionBuilder.addPropertyValue("serverAddress", rpcClientProperties.getServiceAddress());
			beanDefinitionBuilder.addPropertyValue("serverPort", rpcClientProperties.getServicePort());
			
			BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
			rpcRefBeanDefinition.put(field.getName(), beanDefinition);
			
		}
		
	}
	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		// TODO Auto-generated method stub
		this.classLoader = classLoader;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		this.context = applicationContext;
	}

 

}
